package com.tanhua.server.service;

import com.alibaba.fastjson.JSON;
import com.tanhua.autoconfig.templates.AipFaceTemplate;
import com.tanhua.autoconfig.templates.HuanXinTemplate;
import com.tanhua.autoconfig.templates.OssTemplate;
import com.tanhua.autoconfig.templates.SmsTemplate;
import com.tanhua.domain.db.User;
import com.tanhua.domain.db.UserInfo;
import com.tanhua.domain.vo.UserInfoVo;
import com.tanhua.dubbo.api.db.UserApi;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.server.exceptions.TanhuaException;
import com.tanhua.server.utils.JwtUtils;
import com.tanhua.server.utils.UserHolder;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {

//    远程调用dubbo的服务
    @Reference   //远程注入使用的dubbo的Reference
    private UserApi userApi;

    @Reference   //远程注入使用的dubbo的Reference
    private UserInfoApi userInfoApi;

    @Autowired
    private SmsTemplate smsTemplate;

    @Autowired
    private AipFaceTemplate aipFaceTemplate;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private HuanXinTemplate huanXinTemplate;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    public ResponseEntity saveUser(String mobile, String password) {
        User user = new User();
        user.setPassword(DigestUtils.md5Hex(password));
        user.setMobile(mobile);
        user.setCreated(new Date());
        user.setUpdated(new Date());
        Long id = userApi.save(user);
        return ResponseEntity.ok(id);
    }

    public ResponseEntity findByMobile(String mobile) {
        User user = userApi.findByMobile(mobile);
        return ResponseEntity.ok(user);
    }

    String SMS_CODE = "tanhua_code_";

    public ResponseEntity sendCode(String phone) throws Exception {
//        借助阿里云发送短信
//        随机查询6位验证码
//        String code = RandomStringUtils.randomNumeric(6);
        String code = "123456";
//        smsTemplate.sendSms(phone,code);   TODO 以后每天都要发很多此短信，测试期间为了省钱 可以暂时把验证码写死
//        把验证码存储起来，为了和手动输入的做比较，存起来5分钟内有效
//        把验证码存到哪里？？？ 存在redis 5分钟之后会自动失效
        redisTemplate.boundValueOps(SMS_CODE+phone).set(code,5, TimeUnit.MINUTES);
        return ResponseEntity.ok(null);
    }

//    校验验证码并且返回数据：    {"token":"字符串",isNew:true}
    public ResponseEntity loginVerification(String phone, String verificationCode) {
//        1、从redis中获取验证码
        String code = redisTemplate.boundValueOps(SMS_CODE + phone).get();
//        2、判断验证码是否失效 判断是否有值
        if(code==null){
//           throw new RuntimeException("验证码已失效");  // 如果抛异常 状态码默认是500
           throw new TanhuaException(1234,"验证码已失效");  // 如果抛异常 想自己定义状态码
        }
//        3、判断验证码是否一致
        if(!StringUtils.equals(verificationCode,code)){
             throw new TanhuaException(1234,"验证码错误");
        }

        Boolean isNew = false; //定义一个变量 标记是不是新用户
//        4、根据手机号码从数据库中查询   User user
        User user = userApi.findByMobile(phone);
//        5、如果查询不到用户 就直接注册新用户  new User
        if(user==null){
            isNew = true; // 表示是新用户
            user = new User();
            user.setMobile(phone);
            user.setPassword(DigestUtils.md5Hex("123456")); // 随便放一个密码 md5加密
//            user.setUpdated(new Date());
//            user.setCreated(new Date());
            Long userId = userApi.save(user);  //调用api完成用户保存
            user.setId(userId);  // 注意这里需要把id重新放进去

//            调用环信的组件 把用户注册到环信上
            huanXinTemplate.register(userId);

        }
//        6、保存用户信息到服务端  JWT   借助jwt生成一个字符串 ，需要保存到redis中
        String token = JwtUtils.createToken(phone, user.getId(), "itcast");
//        为了根据token字符串判断用户信息
        redisTemplate.boundValueOps("TOKEN_"+token).set(JSON.toJSONString(user),2,TimeUnit.HOURS);
//        7、返回数据  token 就是通过JWT生成的字符串  isNew 是否新用户
//        {"token":"字符串",isNew:true}
        Map resultMap = new HashMap();
        resultMap.put("token",token);
        resultMap.put("isNew",isNew);

//        向MQ中发送一条消息 userId  type  logTime
        Map map = new HashMap(); //根据经验 这里不能泛型
        map.put("userId",user.getId());
        map.put("type", isNew?"0102":"0101"  );  //0101为登录，0102为注册
        map.put("logTime",new DateTime().toString("yyyy-MM-dd"));
        rocketMQTemplate.convertAndSend("tanhua-logs",map);

        System.out.println("MQ消息发送成功---------------------------");

        return ResponseEntity.ok(resultMap);
    }

    public ResponseEntity loginReginfo(String token, UserInfo userInfo) {
        User user = getUserByToken(token); //根据token获取当前用户
        userInfo.setId(user.getId());
//        userInfo.setCreated(new Date());
//        userInfo.setUpdated(new Date());
        userInfoApi.save(userInfo);

        return ResponseEntity.ok(null);
    }

    public User getUserByToken(String token) {  //每一个请求都会进入到这个方法 （除了登录的请求以外）
        String userStr = redisTemplate.boundValueOps("TOKEN_" + token).get();
        if(userStr==null){
            throw new TanhuaException(1234,"请重新登录");
        }
        redisTemplate.boundValueOps("TOKEN_"+token).set(userStr,2,TimeUnit.HOURS);  //重新续命
//        把json字符串反序列化为user对象
        return JSON.parseObject(userStr, User.class);
    }

//    上传用户的头像
    public ResponseEntity loginReginfoHead(MultipartFile headPhoto) throws Exception {
//        1、判断是否为人脸 --- 借助百度AI的人脸识别
        boolean ifFace = aipFaceTemplate.detect(headPhoto.getBytes());
        if(!ifFace){
            throw new TanhuaException(1234,"不是人脸");
        }
//        2、保存图片---借助的阿里云的OSS  返回一个图片的url路径
        String avatar = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());
//        3、更新tb_user_info表中的用户 avatar
        User user = UserHolder.getUser();
//        update tb_user_info set avatar=?? where id=?
        UserInfo userInfo = new UserInfo();
        userInfo.setId(user.getId());
        userInfo.setAvatar(avatar);
//        userInfo.setUpdated(new Date());
        userInfoApi.update(userInfo);
        return ResponseEntity.ok(null);

    }

    public ResponseEntity queryUserInfoById(Long uid) {
      UserInfo userInfo =  userInfoApi.findById(uid);
      UserInfoVo userInfoVo = new UserInfoVo();
//        Object source 源对象数据, Object target 目标
      BeanUtils.copyProperties(userInfo,userInfoVo); // 属性名称和类型一模一样才能拷贝
     if(userInfo.getAge()!=null){
        userInfoVo.setAge(userInfo.getAge().toString());
     }
      return ResponseEntity.ok(userInfoVo);
    }

    public ResponseEntity updateUserInfo(UserInfo userInfo) {
        Long id = UserHolder.getUserId();
        userInfo.setId(id);
//        userInfo.setUpdated(new Date());
        userInfoApi.update(userInfo); //根据id更新
        return ResponseEntity.ok(null);
    }
}
